/*
 * Copyright (c) 2011, Michael van der Westhuizen
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *    - Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    - Redistributions in binary form must reproduce the above
 *      copyright notice, this list of conditions and the following
 *      disclaimer in the documentation and/or other materials provided
 *      with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef PYXMLSEC1_BUFFER_C_MCVDW_20110104
#define PYXMLSEC1_BUFFER_C_MCVDW_20110104

#include "pyxmlsec.h"

#include <xmlsec/buffer.h>
#include <xmlsec/base64.h>



static PyObject * xmlsec1_xmlSecBufferCreate(PyObject * self, PyObject * args, PyObject * kwds)
{
    xmlSecBufferPtr buffer;
    int size_;
    xmlSecSize size;
    PyObject * ret;

    static char * kwlist[] = {"size", NULL};
    buffer = NULL;
    size_ = 0;
    size = 0;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &size_))
    {
        return NULL;
    }

    size = size_;

    if (NULL == (buffer = xmlSecBufferCreate(size)))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferCreate);
        return NULL;
    }

    if (NULL == (ret = xmlsec1mod_wrap_xmlSecBufferPtr(buffer)))
    {
        ENSURE_EXCEPTION_SET(xmlsec1mod_wrap_xmlSecBufferPtr);
        xmlSecBufferDestroy(buffer);
        return NULL;
    }

    return ret;
}



static PyObject * xmlsec1_xmlSecBufferDestroy(PyObject * self, PyObject * obj)
{
    xmlSecBufferPtr buffer;

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    xmlSecBufferDestroy(buffer);
    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferInitialize(PyObject * self, PyObject * args, PyObject * kwds)
{
    xmlSecBufferPtr buffer;
    PyObject * obj;
    int size_;
    xmlSecSize size;

    static char * kwlist[] = {"buffer", "size", NULL};

    buffer = NULL;
    obj = NULL;
    size_ = 0;
    size = 0;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &obj, &size_))
    {
        return NULL;
    }

    size = size_;

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    xmlSecBufferFinalize(buffer);

    if (0 != xmlSecBufferInitialize(buffer, size))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferInitialize);
        return NULL;
    }

    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferSetDefaultAllocMode(PyObject * self, PyObject * args, PyObject * kwds)
{
    int defAllocMode_;
    int defInitialSize_;
    xmlSecAllocMode defAllocMode;
    xmlSecSize defInitialSize;

    static char * kwlist[] = {"defAllocMode", "defInitialSize", NULL};

    defAllocMode_ = (int)xmlSecAllocModeExact;
    defAllocMode = xmlSecAllocModeExact;
    defInitialSize_ = 1;
    defInitialSize = (xmlSecSize)defInitialSize_;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwlist, &defAllocMode_, &defInitialSize_))
    {
        return NULL;
    }

    defAllocMode = (xmlSecAllocMode)defAllocMode_;
    defInitialSize = (xmlSecSize)defInitialSize_;

    xmlSecBufferSetDefaultAllocMode(defAllocMode, defInitialSize);
    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferFinalize(PyObject * self, PyObject * obj)
{
    xmlSecBufferPtr buffer;

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    xmlSecBufferFinalize(buffer);
    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferGetData(PyObject * self, PyObject * obj)
{
    xmlSecBufferPtr buffer;
    xmlSecByte * data;
    PyObject * ret;

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    if (NULL == (data = xmlSecBufferGetData(buffer)))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferGetData);
        return NULL;
    }

    if (NULL == (ret = PyByteArray_FromStringAndSize((const char *)data, (Py_ssize_t)xmlSecBufferGetSize(buffer))))
    {
        ENSURE_EXCEPTION_SET(PyByteArray_FromStringAndSize);
        return NULL;
    }

    return ret;
}



static PyObject * xmlsec1_xmlSecBufferSetData(PyObject * self, PyObject * args, PyObject * kwds)
{
    xmlSecBufferPtr buffer;
    PyObject * obj;
    PyObject * data_;
    xmlSecByte * data;
    xmlSecSize size;

    static char * kwlist[] = {"buf", "data", NULL};

    buffer = NULL;
    data_ = NULL;
    data = NULL;
    size = 0;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &obj, &data_))
    {
        return NULL;
    }

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    if (0 != xmlsec1_ByteArrayOrBytesToXmlSecBytes(data_, &data, &size))
    {
        ENSURE_EXCEPTION_SET(xmlsec1_ByteArrayOrBytesToXmlSecBytes);
        return NULL;
    }

    if (0 != xmlSecBufferSetData(buffer, data, size))
    {
        ENSURE_EXCEPTION_SET(xmlsec1_ByteArrayOrBytesToXmlSecBytes);
        PyMem_Del(data);
        return NULL;
    }

    PyMem_Del(data);
    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferGetSize(PyObject * self, PyObject * obj)
{
    xmlSecBufferPtr buffer;

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    return PyInt_FromLong((long)xmlSecBufferGetSize(buffer));
}



static PyObject * xmlsec1_xmlSecBufferSetSize(PyObject * self, PyObject * args, PyObject * kwds)
{
    xmlSecBufferPtr buffer;
    PyObject * obj;
    int size_;
    xmlSecSize size;

    static char * kwlist[] = {"buf", "size", NULL};

    buffer = NULL;
    obj = NULL;
    size_ = 0;
    size = 0;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &obj, &size_))
    {
        return NULL;
    }

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    size = (xmlSecSize)size_;

    if (0 != xmlSecBufferSetSize(buffer, size))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferSetSize);
        return NULL;
    }

    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferGetMaxSize(PyObject * self, PyObject * obj)
{
    xmlSecBufferPtr buffer;

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    return PyInt_FromLong((long)xmlSecBufferGetMaxSize(buffer));
}



static PyObject * xmlsec1_xmlSecBufferEmpty(PyObject * self, PyObject * obj)
{
    xmlSecBufferPtr buffer;

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    xmlSecBufferEmpty(buffer);
    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferRemoveHead(PyObject * self, PyObject * args, PyObject * kwds)
{
    xmlSecBufferPtr buffer;
    PyObject * obj;
    int size_;
    xmlSecSize size;

    static char * kwlist[] = {"buf", "size", NULL};

    buffer = NULL;
    obj = NULL;
    size_ = 0;
    size = 0;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &obj, &size_))
    {
        return NULL;
    }

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    size = (xmlSecSize)size_;

    if (0 != xmlSecBufferRemoveHead(buffer, size))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferRemoveHead);
        return NULL;
    }

    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferRemoveTail(PyObject * self, PyObject * args, PyObject * kwds)
{
    xmlSecBufferPtr buffer;
    PyObject * obj;
    int size_;
    xmlSecSize size;

    static char * kwlist[] = {"buf", "size", NULL};

    buffer = NULL;
    obj = NULL;
    size_ = 0;
    size = 0;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &obj, &size_))
    {
        return NULL;
    }

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    size = (xmlSecSize)size_;

    if (0 != xmlSecBufferRemoveTail(buffer, size))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferRemoveTail);
        return NULL;
    }

    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferAppend(PyObject * self, PyObject * args, PyObject * kwds)
{
    xmlSecBufferPtr buffer;
    PyObject * obj1;
    PyObject * obj2;
    xmlSecByte * data;
    xmlSecSize size;

    static char * kwlist[] = {"buf", "data", NULL};

    buffer = NULL;
    obj1 = obj2 = NULL;
    data = NULL;
    size = 0;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &obj1, &obj2))
    {
        return NULL;
    }

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj1)))
    {
        return NULL;
    }

    if (0 != xmlsec1_ByteArrayOrBytesToXmlSecBytes(obj2, &data, &size))
    {
        ENSURE_EXCEPTION_SET(xmlsec1_ByteArrayOrBytesToXmlSecBytes);
        return NULL;
    }

    if (0 != xmlSecBufferAppend(buffer, data, size))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferAppend);
        PyMem_Del(data);
        return NULL;
    }

    PyMem_Del(data);
    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferPrepend(PyObject * self, PyObject * args, PyObject * kwds)
{
    xmlSecBufferPtr buffer;
    PyObject * obj1;
    PyObject * obj2;
    xmlSecByte * data;
    xmlSecSize size;

    static char * kwlist[] = {"buf", "data", NULL};

    buffer = NULL;
    obj1 = obj2 = NULL;
    data = NULL;
    size = 0;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &obj1, &obj2))
    {
        return NULL;
    }

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj1)))
    {
        return NULL;
    }

    if (0 != xmlsec1_ByteArrayOrBytesToXmlSecBytes(obj2, &data, &size))
    {
        ENSURE_EXCEPTION_SET(xmlsec1_ByteArrayOrBytesToXmlSecBytes);
        return NULL;
    }

    if (0 != xmlSecBufferPrepend(buffer, data, size))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferPrepend);
        PyMem_Del(data);
        return NULL;
    }

    PyMem_Del(data);
    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferReadFile(PyObject * self, PyObject * args, PyObject * kwds)
{
    xmlSecBufferPtr buffer;
    PyObject * obj1;
    PyObject * obj2;
    PyObject * tmp;
    int ret;

    static char * kwlist[] = {"buf", "filename", NULL};

    buffer = NULL;
    obj1 = obj2 = NULL;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &obj1, &obj2))
    {
        return NULL;
    }

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj1)))
    {
        return NULL;
    }

    if (PyUnicode_Check(obj2))
    {
        if (NULL == (tmp = PyUnicode_AsUTF8String(obj2)))
        {
            ENSURE_EXCEPTION_SET(PyUnicode_AsUTF8String);
            return NULL;
        }

        ret = xmlSecBufferReadFile(buffer, (const char *)PyBytes_AsString(tmp));
        Py_CLEAR(tmp);
    }
    else if (PyBytes_Check(obj2))
    {
        ret = xmlSecBufferReadFile(buffer, (const char *)PyBytes_AsString(obj2));
    }
    else
    {
        PyErr_SetString(PyExc_TypeError, "filename must be if type bytes (string) or unicode");
        return NULL;
    }

    if (0 != ret)
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferReadFile);
        return NULL;
    }

    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferBase64NodeContentRead(PyObject * self, PyObject * args, PyObject * kwds)
{
    xmlSecBufferPtr buffer;
    PyObject * obj1;
    PyObject * obj2;
    xmlNodePtr node;

    static char * kwlist[] = {"buf", "node", NULL};

    buffer = NULL;
    obj1 = obj2 = NULL;
    node = NULL;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &obj1, &obj2))
    {
        return NULL;
    }

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj1)))
    {
        return NULL;
    }

    if (NULL == (node = xmlsec1mod_unwrap_xmlNodePtr(obj2)))
    {
        return NULL;
    }

    if (0 != xmlSecBufferBase64NodeContentRead(buffer, node))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferBase64NodeContentRead);
        return NULL;
    }

    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferBase64NodeContentWrite(PyObject * self, PyObject * args, PyObject * kwds)
{
    xmlSecBufferPtr buffer;
    PyObject * obj1;
    PyObject * obj2;
    xmlNodePtr node;
    int columns;

    static char * kwlist[] = {"buf", "node", "columns", NULL};

    buffer = NULL;
    obj1 = obj2 = NULL;
    node = NULL;
    columns = xmlSecBase64GetDefaultLineSize();

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|i", kwlist, &obj1, &obj2, &columns))
    {
        return NULL;
    }

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj1)))
    {
        return NULL;
    }

    if (NULL == (node = xmlsec1mod_unwrap_xmlNodePtr(obj2)))
    {
        return NULL;
    }

    if (0 != xmlSecBufferBase64NodeContentWrite(buffer, node, columns))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferBase64NodeContentWrite);
        return NULL;
    }   

    Py_RETURN_NONE;
}



static PyObject * xmlsec1_xmlSecBufferCreateOutputBuffer(PyObject * self, PyObject * obj)
{
    xmlSecBufferPtr buffer;
    xmlOutputBufferPtr obuf;
    PyObject * ret;

    if (NULL == (buffer = xmlsec1mod_unwrap_xmlSecBufferPtr(obj)))
    {
        return NULL;
    }

    if (NULL == (obuf = xmlSecBufferCreateOutputBuffer(buffer)))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferCreateOutputBuffer);
        return NULL;
    }

    if (NULL == (ret = xmlsec1mod_wrap_xmlOutputBufferPtr(obuf)))
    {
        ENSURE_EXCEPTION_SET(xmlSecBufferCreateOutputBuffer);
        /* XXX: free? how? doesn't seem particularly well documented - I can't really see this memory every being freed, unless I'm missing something... */
        return NULL;
    }

    return ret;
}

#endif
